home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / gnushogi.lha / gnushogi-1.1 / src / book.c < prev    next >
C/C++ Source or Header  |  1993-04-23  |  31KB  |  1,310 lines

  1. /*
  2.  * book.c - C source for GNU SHOGI
  3.  *
  4.  * Copyright (c) 1993 Matthias Mutz
  5.  *
  6.  * GNU SHOGI is based on GNU CHESS
  7.  *
  8.  * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
  9.  * Foundation
  10.  *
  11.  * This file is part of GNU SHOGI.
  12.  *
  13.  * GNU Shogi is free software; you can redistribute it and/or modify it under
  14.  * the terms of the GNU General Public License as published by the Free
  15.  * Software Foundation; either version 1, or (at your option) any later
  16.  * version.
  17.  *
  18.  * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT ANY
  19.  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  20.  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  21.  * details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License along with
  24.  * GNU Shogi; see the file COPYING.  If not, write to the Free Software
  25.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  26.  */
  27.  
  28. #include "gnushogi.h"
  29. #include "ataks.h"
  30. #ifdef MSDOS
  31. #include <io.h>
  32. #endif
  33. #if !defined MSDOS && !defined THINK_C
  34. #define O_BINARY 0
  35. #endif
  36. #include <fcntl.h>
  37. #ifdef THINK_C
  38. #include <unix.h>
  39. /* #define BOOKTEST */
  40. #endif
  41.  
  42.  
  43.  
  44. unsigned booksize = BOOKSIZE;
  45. unsigned short bookmaxply = BOOKMAXPLY;
  46. unsigned bookcount = 0;
  47.  
  48.  
  49. char *bookfile = NULL;
  50. #ifdef BINBOOK
  51. char *binbookfile = BINBOOK;
  52. #else
  53. char *binbookfile = NULL;
  54. #endif
  55.  
  56.  
  57.  
  58. int GotBook = false;
  59. static char bmvstr[3][7];
  60. long bhashbd, bhashkey;
  61.  
  62.  
  63. void
  64. Balgbr (short int f, short int t, short int flag)
  65.  
  66.  
  67.      /*
  68.       * Generate move strings in different formats.
  69.       */
  70.  
  71. {
  72.   int m3p;
  73.   short promoted = false;
  74.  
  75.   if ( (f & 0x80) != 0)
  76.     {                
  77.       f &= 0x7f;
  78.       promoted = true;
  79.     }
  80.  
  81.   if ( f > NO_SQUARES ) 
  82.     { short piece;
  83.       piece = f - NO_SQUARES;
  84.       if ( f > (NO_SQUARES+NO_PIECES) )
  85.         piece -= NO_PIECES;
  86.       flag = (dropmask | piece); 
  87.     }
  88.   if ( (t & 0x80) != 0 )
  89.     {
  90.       flag |= promote;
  91.       t &= 0x7f;
  92.     }
  93.   if ( f == t && (f != 0 || t != 0) ) 
  94.     { 
  95. #if !defined BAREBONES
  96.       printz("error in algbr: FROM=TO=%d, flag=0x%4x\n",t,flag);
  97. #endif
  98.       bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
  99.     }
  100.   else
  101.   if ( (flag & dropmask) != 0 )
  102.     {
  103.       /* bmvstr[0]: P*3c bmvstr[1]: P'3c */ 
  104.       short piece = flag & pmask;
  105.       bmvstr[0][0] = pxx[piece];
  106.       bmvstr[0][1] = '*';
  107.       bmvstr[0][2] = cxx[column (t)];
  108.       bmvstr[0][3] = rxx[row (t)];
  109.       bmvstr[0][4] = bmvstr[2][0] = '\0';
  110.       strcpy (bmvstr[1], bmvstr[0]);
  111.       bmvstr[1][1] = '\'';
  112.     }
  113.   else
  114.   if (f != 0 || t != 0)
  115.     {
  116.       /* algebraic notation */
  117.       /* bmvstr[0]: 7g7f bmvstr[1]: (+)P7g7f(+) bmvstr[2]: (+)P7f(+) */
  118.       bmvstr[0][0] = cxx[column (f)];
  119.       bmvstr[0][1] = rxx[row (f)];
  120.       bmvstr[0][2] = cxx[column (t)];
  121.       bmvstr[0][3] = rxx[row (t)];
  122.       bmvstr[0][4] = '\0';
  123.       if (promoted)
  124.     {
  125.           bmvstr[1][0] = bmvstr[2][0] = '+';
  126.           bmvstr[1][1] = bmvstr[2][1] = pxx[board[f]];
  127.           strcpy(&bmvstr[1][2],&bmvstr[0][0]);
  128.           strcpy(&bmvstr[2][2],&bmvstr[0][2]);
  129.     }                                  
  130.       else
  131.     {
  132.           bmvstr[1][0] = bmvstr[2][0] = pxx[board[f]];
  133.           strcpy(&bmvstr[1][1],&bmvstr[0][0]);
  134.           strcpy(&bmvstr[2][1],&bmvstr[0][2]);
  135.     }
  136.       if (flag & promote)
  137.         {
  138.           strcat(bmvstr[0], "+");
  139.           strcat(bmvstr[1], "+");
  140.           strcat(bmvstr[2], "+");
  141.         }
  142.     }
  143.   else
  144.     bmvstr[0][0] = bmvstr[1][0] = bmvstr[2][0] = '\0';
  145. }
  146.  
  147.  
  148.  
  149.  
  150. #ifndef QUIETBOOKGEN
  151. void
  152. bkdisplay (s, cnt, moveno)
  153.      char *s;
  154.      int cnt;
  155.      int moveno;
  156. {
  157.     static short pnt;
  158.     struct leaf *node;
  159.     int r, c, l;
  160.  
  161.     pnt = TrPnt[2];
  162.     printf ("matches = %d\n", cnt);
  163.     printf ("inout move is :%s: move number %d side %s\n", 
  164.                 s, moveno / 2 + 1, (moveno & 1) ? "white" : "black");
  165. #ifndef SEMIQUIETBOOKGEN
  166.     printf ("legal moves are \n");
  167.     while (pnt < TrPnt[3])
  168.       {
  169.       node = &Tree[pnt++];
  170.        if ( is_promoted[board[node->f]] )
  171.         Balgbr (node->f | 0x80, node->t, (short) node->flags);
  172.       else
  173.         Balgbr (node->f, node->t, (short) node->flags);
  174.       printf ("%s %s %s\n", 
  175.             bmvstr[0], bmvstr[1], bmvstr[2]);
  176.       }
  177.     printf ("\n current board is\n");
  178.     for (r = (NO_ROWS-1); r >= 0; r--)
  179.     {
  180.       for (c = 0; c <= (NO_COLS-1); c++)
  181.         { char pc;
  182.           l = locn (r, c);
  183.           pc = (is_promoted[board[l]] ? '+' : ' ');
  184.           if (color[l] == neutral)
  185.         printf (" -");
  186.           else if (color[l] == black)
  187.         printf ("%c%c", pc, qxx[board[l]]);
  188.           else
  189.         printf ("%c%c", pc, pxx[board[l]]);
  190.         }
  191.       printf ("\n");
  192.     }
  193.     printf ("\n");
  194.     {  
  195.     short color;
  196.     for (color = black; color <= white; color++)
  197.       { short piece, c;
  198.         printf((color==black)?"black ":"white ");
  199.             for (piece = pawn; piece <= king; piece++)
  200.           if (c = Captured[color][piece]) 
  201.         printf("%i%c ",c,pxx[piece]);
  202.             printf("\n");
  203.           };
  204.     }
  205. #endif /* SEMIQUIETBOOKGEN */
  206. }
  207.  
  208. #endif /* QUIETBOOKGEN */
  209.  
  210. int
  211. BVerifyMove (char *s, short unsigned int *mv, int moveno)
  212.  
  213.      /*
  214.       * Compare the string 's' to the list of legal moves available for the
  215.       * opponent. If a match is found, make the move on the board.
  216.       */
  217.  
  218. {
  219.     static short pnt, tempb, tempc, tempsf, tempst, cnt;
  220.     static struct leaf xnode;
  221.     struct leaf *node;
  222.  
  223.     *mv = 0;
  224.     cnt = 0;
  225.     MoveList (opponent, 2);
  226.     pnt = TrPnt[2];
  227.     while (pnt < TrPnt[3])
  228.       {
  229.       node = &Tree[pnt++];
  230.       if ( is_promoted[board[node->f]] )
  231.         Balgbr (node->f | 0x80, node->t, (short) node->flags);
  232.       else
  233.         Balgbr (node->f, node->t, (short) node->flags);
  234.       if (strcmp (s, bmvstr[0]) == 0 || strcmp (s, bmvstr[1]) == 0 ||
  235.           strcmp (s, bmvstr[2]) == 0)
  236.         {
  237.         cnt++;
  238.         xnode = *node;
  239.         }
  240.       }
  241.     if (cnt == 1)
  242.       {
  243.       MakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
  244.       if (SqAtakd (PieceList[opponent][0], computer))
  245.         {
  246.         UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
  247.         /* Illegal move in check */
  248. #ifndef QUIETBOOKGEN
  249.         printf (CP[77]);
  250.         printf ("\n");
  251.         bkdisplay (s, cnt, moveno);
  252. #endif
  253.         return (false);
  254.         }
  255.       else
  256.         {
  257.         *mv = (xnode.f << 8) | xnode.t;
  258.         if ( is_promoted[board[xnode.t]] )
  259.           Balgbr (xnode.f | 0x80, xnode.t, false);
  260.         else
  261.           Balgbr (xnode.f, xnode.t, false);
  262.         return (true);
  263.         }
  264.       }
  265.     /* Illegal move */
  266. #ifndef QUIETBOOKGEN
  267.     printf (CP[75], s);
  268.     bkdisplay (s, cnt, moveno);
  269. #endif
  270.     return (false);
  271. }
  272.  
  273. void
  274. RESET (void)
  275.  
  276.      /*
  277.       * Reset the board and other variables to start a new game.
  278.       */
  279.  
  280. {
  281.     short int l;
  282.  
  283.     flag.illegal = flag.mate = flag.post = flag.quit = flag.reverse = flag.bothsides = flag.onemove = flag.force = false;
  284.     flag.material = flag.coords = flag.hash = flag.easy = flag.beep = flag.rcptr = true;
  285.     flag.stars = flag.shade = flag.back = flag.musttimeout = false;
  286.     flag.gamein = false;
  287.     GenCnt = 0;
  288.     GameCnt = 0;
  289.     CptrFlag[0] = false;
  290.     opponent = black;
  291.     computer = white;
  292.     for (l = 0; l < NO_SQUARES; l++)
  293.       {
  294.       board[l] = Stboard[l];
  295.       color[l] = Stcolor[l];
  296.       Mvboard[l] = 0;
  297.       }
  298.     ClearCaptured ();
  299.     InitializeStats ();
  300.     hashbd = hashkey = 0; 
  301. }
  302.  
  303. int
  304. Vparse (FILE * fd, unsigned short *mv, short int side, char *opening, int moveno)
  305. {
  306.     register int c, i;
  307.     char s[128];
  308.     char *p;
  309.  
  310.     while (true)
  311.       {
  312.           
  313.       while ((c = getc (fd)) == ' ' || c == '!' || c == '/' || c == '\n');
  314.  
  315.       if ( c == '(' ) 
  316.         {     /* amount of time spent for the last move */
  317.         while ((c = getc(fd)) != ')' && c != EOF);
  318.         if ( c == ')' ) 
  319.           while ((c = getc (fd)) == ' ' || c == '\n');
  320.         }
  321.  
  322.       if (c == '[')
  323.         {     /* comment for the actual game */
  324.         while ( (c = getc(fd)) != ']' && c != EOF );
  325.         if ( c == ']' ) 
  326.           while ((c = getc (fd)) == ' ' || c == '\n');
  327.         }
  328.           
  329.       if (c == '\r')
  330.           continue;
  331.  
  332.       if (c == '#')
  333.         {    /* comment */
  334.         p = opening;
  335.         do
  336.           {
  337.               *p++ = c;
  338.               c = getc (fd);
  339.               if (c == '\r')
  340.               continue;
  341.               /* goes to end of line */
  342.               if (c == '\n')
  343.             {
  344.                 *p = '\0';
  345.                 return 0;
  346.                 } 
  347.               if (c == EOF)
  348.             return -1;
  349.           }
  350.         while (true);
  351.         }
  352.  
  353.       s[i = 0] = (char) c;
  354.  
  355.           while ( c >= '0' && c <= '9' )
  356.         { 
  357.           c = getc(fd);
  358.           s[++i] = (char) c;
  359.         }
  360.  
  361.       if ( c == '.' )
  362.         { 
  363.           while ((c = getc (fd)) == ' ' || c == '.' || c == '\n');
  364.           s[i = 0] = (char) c;
  365.         }     
  366.  
  367.       while ((c = getc (fd)) != '?' && c != '!' && c != ' ' && c != '(' && c != '\n' && c != '\t' && c != EOF)
  368.         {
  369.         if (c == '\r')
  370.             continue;
  371.         if (c != 'x' && c != '-' && c != ',' && c != ';' && c != '=')
  372.             s[++i] = (char) c;
  373.         }
  374.       s[++i] = '\0';
  375.  
  376.       if ( c == '(' ) 
  377.         {
  378.           while ((c = getc(fd)) != ')' && c != EOF);
  379.           if ( c == ')' ) 
  380.         c = getc(fd);
  381.         }
  382.  
  383.       if (c == EOF)
  384.           return (-1);
  385.  
  386.       if (s[0] == '#')
  387.         {
  388.         while (c != '\n' && c != EOF)
  389.             c = getc (fd);
  390.         if (c == EOF)
  391.             return -1;
  392.         else
  393.             return (0);
  394.         }
  395.  
  396.       if (strcmp (s, "draw") == 0)
  397.           continue;
  398.       else if (strcmp (s, "1-0") == 0)
  399.           continue;
  400.       else if (strcmp (s, "0-1") == 0)
  401.           continue;
  402.       else if (strcmp (s, "Resigns") == 0)
  403.           continue;
  404.       else if (strcmp (s, "Resigns.") == 0)
  405.           continue;
  406.       else if (strcmp (s, "Sennichite") == 0)
  407.           continue;
  408.       else if (strcmp (s, "Sennichite.") == 0)
  409.           continue;
  410.       else if (strcmp (s, "Jishogi") == 0)
  411.           continue;
  412.       else if (strcmp (s, "Jishogi.") == 0)
  413.           continue;
  414.  
  415.       bhashkey = hashkey;
  416.       bhashbd = hashbd;
  417.  
  418.       i = BVerifyMove (s, mv, moveno);
  419.  
  420.       if (c == '?')
  421.         {            /* Bad move, not for the program to play */
  422.         *mv |= BADMOVE;    /* Flag it ! */
  423.         while ((c = getc (fd)) == '?' || c == '!' || c == '/');
  424.         }
  425.       else if (c == '!')
  426.         {            /* Good move */
  427.         while ((c = getc (fd)) == '?' || c == '!' || c == '/');
  428.         }
  429.       else if (c == '\r')
  430.           c = getc (fd);
  431.  
  432.       if ( c == '(' ) 
  433.         while ((c = getc(fd)) != ')' && c != EOF);
  434.  
  435.       if (!i)
  436.         {
  437.         printf ("%s \n", opening);
  438.         /* flush to start of next */
  439.         while ((c = getc (fd)) != '#' && c != EOF);
  440.         if (c == EOF)
  441.             return -1;
  442.         else
  443.           {
  444.               ungetc (c, fd);
  445.               return i;
  446.           }
  447.         }
  448.  
  449.       return (i);
  450.       }
  451. }
  452.  
  453.  
  454. #ifdef GDX       
  455.  
  456.  
  457. struct gdxadmin
  458. {
  459.     unsigned int bookcount;
  460.     unsigned int booksize;
  461.     unsigned long maxoffset;
  462. } ADMIN, B;
  463.  
  464. struct gdxdata
  465. {
  466.     unsigned long hashbd;
  467.     unsigned short hashkey;
  468.     unsigned short bmove;
  469.     unsigned short flags; /* flag LASTMOVE */
  470.     unsigned short hint;
  471.     unsigned short count;
  472. } DATA;
  473.  
  474. #ifdef LONG64
  475. #define lts(x) (((x>>48)&0xfffe)|side)
  476. #else
  477. #if defined THINK_C || defined USE_LTSIMP
  478.  
  479. static unsigned short ltsimp (long x)
  480. { unsigned short n;
  481.   n = (((x>>16)&0xfffe));
  482. #if 0
  483.   printf("x=0x%lx lts(x)=0x%x\n",x,n);
  484. #endif
  485.   return(n);
  486. }
  487. #define lts(x) (ltsimp(x) | side)
  488. #else
  489. #define lts(x) (((x>>16)&0xfffe)|side)
  490. #endif
  491. #endif
  492. unsigned long currentoffset;
  493. int gfd;
  494.  
  495. void
  496. GetOpenings (void)
  497.  
  498.      /*
  499.       * Read in the Opening Book file and parse the algebraic notation for a move
  500.       * into an unsigned integer format indicating the from and to square. Create
  501.       * a linked list of opening lines of play, with entry->next pointing to the
  502.       * next line and entry->move pointing to a chunk of memory containing the
  503.       * moves. More Opening lines of up to 100 half moves may be added to
  504.       * gnuchess.book. But now its a hashed table by position which yields a move
  505.       * or moves for each position. It no longer knows about openings per say only
  506.       * positions and recommended moves in those positions.
  507.       */
  508. {
  509.     register short int i;
  510.     char opening[80];
  511.     char msg[80];
  512.     int mustwrite = false;
  513.     unsigned short xside, doit, side;
  514.     short int c;
  515.     unsigned short mv;
  516.     unsigned short ix;
  517.     unsigned int x;
  518.     unsigned int games = 0;
  519.  
  520.     FILE *fd;
  521.  
  522.     if ((fd = fopen (bookfile, "r")) == NULL)
  523.     fd = fopen ("gnushogi.book", "r");
  524.     if (fd != NULL)
  525.       {
  526.       /* yes add to book */
  527.       /* open book as writer */
  528.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  529.       if (gfd >= 0)
  530.         {
  531.         if (sizeof(struct gdxadmin) == read (gfd, (char *)&ADMIN, sizeof (struct gdxadmin)))
  532.           {
  533.               B.bookcount = ADMIN.bookcount;
  534.               B.booksize = ADMIN.booksize;
  535.               B.maxoffset = ADMIN.maxoffset;
  536.               if (B.booksize && !(B.maxoffset == ((unsigned long)(B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  537.             {
  538.                 printf ("bad format %s\n", binbookfile);
  539.                 exit (1);
  540.             }
  541.           }
  542.         else
  543.           {
  544.               printf ("bad format %s\n", binbookfile);
  545.               exit (1);
  546.           }
  547.         close (gfd);
  548.                 gfd = open (binbookfile, O_RDWR | O_BINARY);
  549.  
  550.         }
  551.       else
  552.         {
  553. #ifdef THINK_C
  554.                 gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY);
  555. #else
  556.                 gfd = open (binbookfile, O_RDWR | O_CREAT | O_BINARY, 0644);
  557. #endif
  558.         ADMIN.bookcount = B.bookcount = 0;
  559.         ADMIN.booksize = B.booksize = booksize;
  560.                 B.maxoffset = ADMIN.maxoffset = (unsigned long) (booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  561.         DATA.hashbd = 0;
  562.         DATA.hashkey = 0;
  563.         DATA.bmove = 0;
  564.         DATA.flags = 0;
  565.         DATA.hint = 0;
  566.         DATA.count = 0;
  567.         write (gfd, (char *)&ADMIN, sizeof (struct gdxadmin));
  568.         printf ("creating bookfile %s  %ld %d\n", binbookfile, B.maxoffset, B.booksize);
  569.         for (x = 0; x < B.booksize; x++)
  570.           {
  571.               write (gfd, (char *)&DATA, sizeof (struct gdxdata));
  572.           }
  573.  
  574.  
  575.         }
  576.       if (gfd >= 0)
  577.         {
  578.  
  579.  
  580.         /* setvbuf(fd,buffr,_IOFBF,2048); */
  581.         side = black;
  582.         xside = white;
  583.         hashbd = hashkey = 0;
  584.         i = 0;
  585.  
  586.         while ((c = Vparse (fd, &mv, side, opening, i)) >= 0)
  587.           {
  588.               if (c == 1)
  589.                         {
  590.  
  591.                 /*
  592.                              * if not first move of an opening and first
  593.                              * time we have seen it save next move as
  594.                              * hint
  595.                              */
  596.                 i++;
  597.                 if (i < bookmaxply + 2)
  598.                   {
  599.                   if (i > 1)
  600.                     {
  601.                     DATA.hint = mv & 0x7fff;
  602.                     }
  603.                   if (i < bookmaxply + 1)
  604.                     {
  605.                     doit = true;
  606.  
  607.                     /*
  608.                                  * see if this position and
  609.                                  * move already exist from
  610.                                  * some other opening
  611.                                  */
  612.  
  613.                     /*
  614.                                  * is this ethical, to offer
  615.                                  * the bad move as a
  616.                                  * hint?????
  617.                                  */
  618.                     ix = 0;
  619.                     if (mustwrite)
  620.                       {
  621.                           lseek (gfd, currentoffset, SEEK_SET);
  622.                           write (gfd, (char *)&DATA, sizeof (struct gdxdata));
  623.                           mustwrite = false;
  624.                       }
  625.                     doit = true;
  626.                                         currentoffset = (unsigned long) ((unsigned long)bhashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  627.                     while (true)
  628.                       {
  629.  
  630.                           lseek (gfd, currentoffset, SEEK_SET);
  631.                           if ((read (gfd, (char *)&DATA, sizeof (struct gdxdata)) == 0))
  632.                             break;
  633.  
  634.                           if (DATA.bmove == 0) break;
  635.                           if (DATA.hashkey == (unsigned short)(lts(bhashkey)) && 
  636.                               DATA.hashbd == (unsigned long)bhashbd)
  637.                         {                                 
  638.                             if (DATA.bmove == mv)
  639.                               {
  640.                               DATA.count++;
  641.                                                           /*
  642.                                            * yes so just bump count - count is
  643.                                            * used to choose opening move in
  644.                                            * proportion to its presence in the book
  645.                                            */
  646.                               doit = false;
  647.                               mustwrite = true;
  648.                               break;   
  649.                               } else if(DATA.flags & LASTMOVE){
  650.                             DATA.flags &= (~LASTMOVE);    
  651.                                   lseek (gfd, currentoffset, SEEK_SET);
  652.                                   write (gfd, (char *)&DATA, sizeof (struct gdxdata));
  653.                             }
  654.                         }
  655.                           currentoffset += (unsigned long)sizeof (struct gdxdata);
  656.                           if (currentoffset > B.maxoffset)
  657.                           currentoffset = (unsigned long)sizeof (struct gdxadmin);
  658.                       }
  659.  
  660.                     /*
  661.                                  * doesn`t exist so add it to
  662.                                  * the book
  663.                                  */
  664.                     if (!mustwrite)
  665.                       {
  666.                           B.bookcount++;
  667. #if !defined BAREBONES
  668. #ifdef THINK_C
  669.                           if (B.bookcount % 100 == 0)
  670. #else
  671.                           if (B.bookcount % 1000 == 0)
  672. #endif
  673.                           printf ("%d rec %d openings processed\n", B.bookcount,games);
  674. #endif
  675.                           /* initialize a record */
  676.                           DATA.hashbd = (unsigned long)bhashbd;
  677.                           DATA.hashkey = (unsigned short)(lts(bhashkey));
  678.                           DATA.bmove = mv;
  679.                           DATA.flags = LASTMOVE;
  680.                           DATA.count = 1;
  681.                           DATA.hint = 0;
  682.                           mustwrite = true;
  683.                       }
  684.                     }
  685.                   }
  686.                 computer = opponent;
  687.                 opponent = computer ^ 1;
  688.  
  689.                 xside = side;
  690.                 side = side ^ 1;
  691.             }
  692.               else if (i > 0)
  693.             {
  694.                 /* reset for next opening */
  695.                 games++;
  696.                 if (mustwrite)
  697.                   {
  698.                   lseek (gfd, currentoffset, SEEK_SET);
  699.                   write (gfd, (char *)&DATA, sizeof (struct gdxdata));
  700.                   mustwrite = false;
  701.                   }
  702.                 RESET ();
  703.                 i = 0;
  704.                 side = black;
  705.                 xside = white;
  706.                 hashbd = hashkey = 0;
  707.  
  708.             }
  709.           }
  710.         if (mustwrite)
  711.           {
  712.               lseek (gfd, currentoffset, SEEK_SET);
  713.               write (gfd, (char *)&DATA, sizeof (struct gdxdata));
  714.               mustwrite = false;
  715.           }
  716.         fclose (fd);
  717.         /* write admin rec with counts */
  718.         ADMIN.bookcount = B.bookcount;
  719.         currentoffset = 0;
  720.         lseek (gfd, currentoffset, 0);
  721.         write (gfd, (char *)&ADMIN, sizeof (struct gdxadmin));
  722.  
  723.         close (gfd);
  724.         }
  725.       }
  726.     if (binbookfile != NULL)
  727.       {
  728.       /* open book as writer */
  729.       gfd = open (binbookfile, O_RDONLY | O_BINARY);
  730.       if (gfd >= 0)
  731.         {
  732.         read (gfd, (char *)&ADMIN, sizeof (struct gdxadmin));
  733.         B.bookcount = ADMIN.bookcount;
  734.         B.booksize = ADMIN.booksize;
  735.         B.maxoffset = ADMIN.maxoffset;
  736.                 if (B.booksize && !(B.maxoffset == ((unsigned long) (B.booksize - 1) * sizeof (struct gdxdata) + sizeof (struct gdxadmin))))
  737.           {
  738.               printf ("bad format %s\n", binbookfile);
  739.               exit (1);
  740.           }
  741.  
  742.         }
  743.       else
  744.         {
  745.         B.bookcount = 0;
  746.         B.booksize = booksize;
  747.  
  748.         }
  749.  
  750. #if !defined BAREBONES 
  751.       sprintf (msg, CP[213], B.bookcount, B.booksize);
  752.       ShowMessage (msg);
  753. #endif
  754.       }
  755.     /* set every thing back to start game */
  756.     Book = BOOKFAIL;
  757.     RESET ();
  758.     /* now get ready to play */
  759.     if (!B.bookcount)
  760.       {
  761. #if !defined BAREBONES
  762.       ShowMessage (CP[212]);
  763. #endif
  764.       Book = 0;
  765.       }
  766. }
  767.  
  768.  
  769. int
  770. OpeningBook (unsigned short *hint, short int side)
  771.  
  772.      /*
  773.       * Go thru each of the opening lines of play and check for a match with the
  774.       * current game listing. If a match occurs, generate a random number. If this
  775.       * number is the largest generated so far then the next move in this line
  776.       * becomes the current "candidate". After all lines are checked, the
  777.       * candidate move is put at the top of the Tree[] array and will be played by
  778.       * the program. Note that the program does not handle book transpositions.
  779.       */
  780.  
  781. {
  782.     unsigned short r, m;
  783.     int possibles = TrPnt[2] - TrPnt[1];
  784.  
  785.     gsrand ((unsigned int) time ((long *) 0));
  786.     m = 0;
  787.  
  788.     /*
  789.      * find all the moves for this position  - count them and get their
  790.      * total count
  791.      */
  792.     {
  793.     register unsigned short i, x;
  794.     register unsigned short rec = 0;
  795.     register unsigned short summ = 0;
  796.     register unsigned short h = 0, b = 0;
  797.     struct gdxdata OBB[128];
  798. #ifdef BOOKTEST
  799.         printf("looking for book move, hashbd = 0x%lx lts(hashkey) = 0x%x\n",
  800.                   (unsigned long)hashbd,(unsigned short)lts(hashkey));
  801. #endif
  802.     if (B.bookcount == 0)
  803.       {
  804.           Book--;
  805.           return false;
  806.       }
  807.         currentoffset = (unsigned long) ((unsigned long)hashkey % B.booksize) * sizeof (struct gdxdata) + sizeof (struct gdxadmin);
  808.     x = 0;
  809.     lseek (gfd, currentoffset, 0);
  810.     while (true)
  811.       {
  812.           if (read (gfd, (char *)&OBB[x], sizeof (struct gdxdata)) == 0)
  813.             break;
  814.           if (OBB[x].bmove == 0) break;
  815.           if (OBB[x].hashkey == (unsigned short)(lts(hashkey)) && 
  816.               OBB[x].hashbd == (unsigned long)hashbd)
  817.         {
  818.             x++;if(OBB[x-1].flags & LASTMOVE) break;
  819.         }
  820.         currentoffset += sizeof (struct gdxdata); 
  821.           if (currentoffset > B.maxoffset){
  822.           lseek (gfd, sizeof (struct gdxadmin), 0);
  823.           currentoffset += sizeof (struct gdxadmin); 
  824.         }
  825.  
  826.       }
  827. #ifdef BOOKTEST
  828.         printf("%d book move(s) found.\n",x);
  829. #endif
  830.     if (x == 0)
  831.       {
  832.           Book--;
  833.           return false;
  834.       }
  835.     for (i = 0; i < x; i++)
  836.       {
  837.           if ((m = OBB[i].bmove) & BADMOVE)
  838.         {
  839.             m ^= BADMOVE;
  840.             /* is the move is in the MoveList */
  841.             for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  842.               {
  843.               if (((Tree[b].f << 8) | Tree[b].t) == m)
  844.                 {
  845.  
  846.                 if (--possibles)
  847.                     Tree[b].score = DONTUSE;
  848.                 break;
  849.                 }
  850.               }
  851.         }
  852.           else 
  853.         {
  854. #if defined DEBUG || defined BOOKTEST
  855.            char s[20];
  856.           movealgbr(m = OBB[i].bmove,s); 
  857.           printf("finding book move: %s\n",s);
  858. #endif
  859.           summ += OBB[i].count;
  860.         }
  861.       }
  862.     if (summ == 0)
  863.           {
  864.               Book--;
  865.               return false;
  866.           }
  867.  
  868.     r = (urand () % summ);
  869.     for (i = 0; i < x; i++)
  870.         if (!(OBB[i].bmove & BADMOVE) ){
  871.             if( r < OBB[i].count)
  872.                 {
  873.                 rec = i;
  874.                 break;
  875.                 }
  876.               else
  877.               r -= OBB[i].count;
  878.         } 
  879.  
  880.     h = ((OBB[rec].hint) & 0x7fff);
  881.     m = ((OBB[rec].bmove) & 0x7fff);
  882.     /* make sure the move is in the MoveList */
  883.     for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
  884.       {
  885.           if (((Tree[b].f << 8) | Tree[b].t) == m)
  886.         {
  887.             Tree[b].flags |= book;
  888.             Tree[b].score = 0;
  889.             break;
  890.         }
  891.       }
  892.     /* Make sure its the best */
  893.  
  894.     pick (TrPnt[1], TrPnt[2] - 1);
  895.     if (Tree[TrPnt[1]].score)
  896.       {
  897.           /* no! */
  898.           Book--;
  899.           return false;
  900.       }
  901.     /* ok pick up the hint and go */
  902.     *hint = h;
  903.     return true;
  904.     }
  905.     Book--;
  906.     return false;
  907. }
  908.  
  909.  
  910.  
  911. #else /* memory based */
  912.  
  913.  
  914. unsigned int BKTBLSIZE;
  915. unsigned long BOOKMASK;
  916. unsigned bookpocket = BOOKPOCKET;
  917.  
  918. static struct bookentry
  919. {
  920.     unsigned long bookkey;
  921.     unsigned long bookbd;
  922.     unsigned short bmove;
  923.     unsigned short hint;
  924.     unsigned short count;
  925.     unsigned short flags;
  926. } *OBEND;
  927.  
  928. struct bookentry *OpenBook = NULL;
  929. static struct bookentry **BookTable;
  930.  
  931.  
  932. static void
  933. bkalloc (unsigned bksize)
  934. {
  935.     register int i, f;
  936.     /* allocate space for the book */
  937.     f = (bksize + bookpocket - 1) / bookpocket;
  938.     bksize = booksize = f * bookpocket;
  939. #ifdef MSDOS
  940.     OpenBook = (struct bookentry *) _halloc (bksize * sizeof (struct bookentry));
  941. #else
  942.     OpenBook = (struct bookentry *) malloc (bksize * sizeof (struct bookentry));
  943. #endif
  944.     if (OpenBook == NULL)
  945.       {
  946.       perror ("memory alloc");
  947.       exit (1);
  948.       }
  949.     for (BKTBLSIZE = 1, BOOKMASK = 1; BKTBLSIZE < f; BKTBLSIZE *= 2, BOOKMASK = (BOOKMASK << 1));
  950.     BOOKMASK -= 1;
  951.     BookTable = (struct bookentry **) malloc (BKTBLSIZE * sizeof (struct bookentry *));
  952.     if (BookTable == NULL)
  953.       {
  954.       perror ("memory alloc");
  955.       exit (1);
  956.       }
  957.     for (i = 0; i < BKTBLSIZE; i++)
  958.       {
  959.       BookTable[i] = &OpenBook[bksize / BKTBLSIZE * i];
  960.       }
  961.     OBEND = (OpenBook + ((bksize) * sizeof (struct bookentry)));
  962. }
  963.  
  964. void
  965. GetOpenings (void)
  966.  
  967. /*
  968.  * Read in the Opening Book file and parse the algebraic notation for a move
  969.  * into an unsigned integer format indicating the from and to square. Create
  970.  * a linked list of opening lines of play, with entry->next pointing to the
  971.  * next line and entry->move pointing to a chunk of memory containing the
  972.  * moves. More Opening lines of up to 100 half moves may be added to
  973.  * gnuchess.book. But now its a hashed table by position which yields a move
  974.  * or moves for each position. It no longer knows about openings per say only
  975.  * positions and recommended moves in those positions.
  976.  */
  977. {
  978.     FILE *fd;
  979.     register struct bookentry *OB = NULL;
  980.     register struct bookentry *OC = NULL;
  981.     register short int i;
  982.     char opening[80];
  983.     char msg[80];
  984.     unsigned short xside, doit, side;
  985.     short int c;
  986.     unsigned short mv;
  987.  
  988.     if (binbookfile != NULL)
  989.       {
  990. #ifdef THINK_C
  991.       fd = fopen (binbookfile, RWA_ACC);
  992. #else
  993.       fd = fopen (binbookfile, "r");
  994. #endif
  995.       if (fd != NULL)
  996.         {
  997.         fscanf (fd, "%d\n", &booksize);
  998.         fscanf (fd, "%d\n", &bookcount);
  999.         fscanf (fd, "%d\n", &bookpocket);
  1000.         bkalloc (booksize);
  1001. #if !defined BAREBONES
  1002.         sprintf (msg, CP[213], bookcount, booksize);
  1003.         ShowMessage (msg);
  1004. #endif
  1005.         if (0 > fread (OpenBook, sizeof (struct bookentry), booksize, fd))
  1006.           {
  1007.               perror ("fread");
  1008.               exit (1);
  1009.           }
  1010.         /* set every thing back to start game */
  1011.         Book = BOOKFAIL;
  1012.         for (i = 0; i < NO_SQUARES; i++)
  1013.           {
  1014.               board[i] = Stboard[i];
  1015.               color[i] = Stcolor[i];
  1016.           }
  1017.                  ClearCaptured ();
  1018.         /* InitializeStats (); Mutz, 2.2.93 */
  1019.         fclose (fd);
  1020.  
  1021.         }
  1022.       }
  1023.     if ((fd = fopen (bookfile, "r")) == NULL)
  1024.     fd = fopen ("gnushogi.book", "r");
  1025.     if (fd != NULL)
  1026.       {
  1027.  
  1028.       if (OpenBook == NULL)
  1029.         {
  1030.         bkalloc (booksize);
  1031.         for (OB = OpenBook; OB < &OpenBook[booksize]; OB++)
  1032.             OB->count = 0;
  1033.         }
  1034.       OC = NULL;
  1035.       /* setvbuf(fd,buffr,_IOFBF,2048); */
  1036.       side = black;
  1037.       xside = white;
  1038.       hashbd = hashkey = 0;
  1039.       i = 0;
  1040.  
  1041.       while ((c = Vparse (fd, &mv, side, opening, i)) >= 0)
  1042.         {
  1043.         if (c == 1)
  1044.           {
  1045.  
  1046.               /*
  1047.                * if not first move of an opening and first
  1048.                * time we have seen it save next move as
  1049.                * hint
  1050.                */
  1051.               i++;
  1052.               if (i < bookmaxply + 2)
  1053.             {
  1054.                 if (i > 1 && OB->count == 1)
  1055.                 OB->hint = mv & 0x7fff;
  1056.                 OC = OB;    /* save for end marking */
  1057.                 if (i < bookmaxply + 1)
  1058.                   {
  1059.                   doit = true;
  1060.  
  1061.                   /*
  1062.                        * see if this position and
  1063.                        * move already exist from
  1064.                        * some other opening
  1065.                        */
  1066.  
  1067.                   /*
  1068.                        * is this ethical, to offer
  1069.                        * the bad move as a
  1070.                        * hint?????
  1071.                        */
  1072.                   OB = BookTable[bhashkey & BOOKMASK];
  1073.                   while (OB->count)
  1074.                     {
  1075.                     if (OB->bookkey == (unsigned long)bhashkey
  1076.                         && OB->bookbd == (unsigned long)bhashbd
  1077.                         && (OB->flags & SIDEMASK) == side
  1078.                         && OB->bmove == mv)
  1079.                       {
  1080.  
  1081.                           /*
  1082.                            * yes so * just bump * count - * count is * used to
  1083.                            * choose * opening * move in * proportion * to its
  1084.                            * presence * in the * book
  1085.                            */
  1086.                           doit = false;
  1087.                           OB->count++;
  1088.                           break;
  1089.                       }
  1090.  
  1091.                     /*
  1092.                          * Book is hashed
  1093.                          * into BKTBLSIZE
  1094.                          * chunks based on
  1095.                          * hashkey
  1096.                          */
  1097.                     if (++OB == OBEND)
  1098.                         OB = OpenBook;
  1099.                     }
  1100.  
  1101.                   /*
  1102.                        * doesn`t exist so add it to
  1103.                        * the book
  1104.                        */
  1105.                   if (doit)
  1106.                     {
  1107.                     bookcount++;
  1108.                     if (bookcount > (booksize - 2 * BKTBLSIZE))
  1109.                       {
  1110.                           printf ("booksize exceeded\n");
  1111.                           exit (1);
  1112.                       }
  1113. #if !defined BAREBONES
  1114.                     if (bookcount % 1000 == 0)
  1115.                         printf ("%d processed\n", bookcount);
  1116. #endif
  1117.                     OB->bookkey = (unsigned long)bhashkey;
  1118.                     OB->bookbd = (unsigned long)bhashbd;
  1119.                     OB->bmove = mv;
  1120.                     OB->hint = 0;
  1121.                     OB->count = 1;
  1122.                     OB->flags = side;
  1123.                     }
  1124.                   }
  1125.             }
  1126.               computer = opponent;
  1127.               opponent = computer ^ 1;
  1128.  
  1129.               xside = side;
  1130.               side = side ^ 1;
  1131.           }
  1132.         else if (i > 0)
  1133.           {
  1134.               /* reset for next opening */
  1135.               RESET ();
  1136.               i = 0;
  1137.               side = black;
  1138.               xside = white;
  1139.               hashbd = hashkey = 0;
  1140.  
  1141.           }
  1142.         }
  1143.       fclose (fd);
  1144.       if (binbookfile != NULL)
  1145.         {
  1146. #ifdef THINK_C
  1147.         fd = fopen (binbookfile, WA_ACC);
  1148. #else
  1149.         fd = fopen (binbookfile, "w");
  1150. #endif
  1151.         if (fd != NULL)
  1152.           {
  1153.               fprintf (fd, "%d\n%d\n%d\n", booksize, bookcount, bookpocket);
  1154.               if (0 > fwrite (OpenBook, sizeof (struct bookentry), booksize, fd))
  1155.                 perror ("fwrite");
  1156.               fclose (fd);
  1157.               binbookfile = NULL;
  1158.           }
  1159.         }
  1160. #if !defined BAREBONES
  1161.       sprintf (msg, CP[213], bookcount, booksize);
  1162.       ShowMessage (msg);
  1163. #endif
  1164.       /* set every thing back to start game */
  1165.       Book = BOOKFAIL;
  1166.       RESET ();
  1167.       }
  1168.     else if (OpenBook == NULL)
  1169.       {
  1170. #if !defined BAREBONES
  1171.       if (!bookcount)
  1172.           ShowMessage (CP[212]);
  1173. #endif
  1174.       Book = 0;
  1175.       }
  1176. }
  1177.  
  1178.  
  1179. int
  1180. OpeningBook (unsigned short *    hint, short int side)
  1181.  
  1182. /*
  1183.  * Go thru each of the opening lines of play and check for a match with the
  1184.  * current game listing. If a match occurs, generate a random number. If this
  1185.  * number is the largest generated so far then the next move in this line
  1186.  * becomes the current "candidate". After all lines are checked, the
  1187.  * candidate move is put at the top of the Tree[] array and will be played by
  1188.  * the program. Note that the program does not handle book transpositions.
  1189.  */
  1190.  
  1191. {
  1192.     short pnt;
  1193.     unsigned short m;
  1194.     unsigned r, cnt, tcnt, ccnt;
  1195.     register struct bookentry *OB, *OC;
  1196.     int possibles = TrPnt[2] - TrPnt[1];
  1197.  
  1198.     gsrand ((unsigned int) time ((long *) 0));
  1199.     m = 0;
  1200.     cnt = 0;
  1201.     tcnt = 0;
  1202.     ccnt = 0;
  1203.     OC = NULL;
  1204.  
  1205.  
  1206.     /*
  1207.      * find all the moves for this position  - count them and get their
  1208.      * total count
  1209.      */
  1210.     OB = BookTable[hashkey & BOOKMASK];
  1211.     while (OB->count)
  1212.       {
  1213.       if (OB->bookkey == (unsigned long)hashkey
  1214.           && OB->bookbd == (unsigned long)hashbd
  1215.           && ((OB->flags) & SIDEMASK) == side)
  1216.         {
  1217.         if (OB->bmove & BADMOVE)
  1218.           {
  1219.               m = OB->bmove ^ BADMOVE;
  1220.               /* is the move is in the MoveList */
  1221.               for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1222.             {
  1223.                 if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  1224.                   {
  1225.                   if (--possibles)
  1226.                     {
  1227.                     Tree[pnt].score = DONTUSE;
  1228.                     break;
  1229.                     }
  1230.                   }
  1231.             }
  1232.  
  1233.           }
  1234.         else
  1235.           {
  1236.               OC = OB;
  1237.               cnt++;
  1238.               tcnt += OB->count;
  1239.           }
  1240.         }
  1241.       if (++OB == OBEND)
  1242.           OB = OpenBook;
  1243.       }
  1244.     /* if only one just do it */
  1245.     if (cnt == 1)
  1246.       {
  1247.       m = OC->bmove;
  1248.       }
  1249.     else
  1250.     /* more than one must choose one at random */
  1251.     if (cnt > 1)
  1252.       {
  1253.       /* pick a number */
  1254.       r = urand () % 1000;
  1255.  
  1256.       OC = BookTable[hashkey & BOOKMASK];
  1257.       while (OC->count)
  1258.         {
  1259.         if (OC == OBEND)
  1260.             OC = OpenBook;
  1261.         if (OC->bookkey == (unsigned long)hashkey
  1262.             && OC->bookbd == (unsigned long)hashbd
  1263.             && ((OC->flags) & SIDEMASK) == side
  1264.             && !(OC->bmove & BADMOVE))
  1265.           {
  1266.               ccnt += OC->count;
  1267.               if (((unsigned long) (ccnt * BOOKRAND) / tcnt) >= r)
  1268.             {
  1269.                 m = OC->bmove;
  1270.                 break;
  1271.             }
  1272.           }
  1273.         if (++OC == OBEND)
  1274.             OC = OpenBook;
  1275.         }
  1276.       }
  1277.     else
  1278.       {
  1279.       /* none decrement count of no finds */
  1280.       Book--;
  1281.       return false;
  1282.       }
  1283.     /* make sure the move is in the MoveList */
  1284.     for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
  1285.       {
  1286.       if (((Tree[pnt].f << 8) | Tree[pnt].t) == m)
  1287.         {
  1288.         Tree[pnt].flags |= book;
  1289.         Tree[pnt].score = 0;
  1290.         break;
  1291.         }
  1292.       }
  1293.     /* Make sure its the best */
  1294.  
  1295.     pick (TrPnt[1], TrPnt[2] - 1);
  1296.     if (Tree[TrPnt[1]].score)
  1297.       {
  1298.       /* no! */
  1299.       Book--;
  1300.       return false;
  1301.       }
  1302.     /* ok pick up the hint and go */
  1303.     *hint = OC->hint;
  1304.     return true;
  1305. }
  1306.  
  1307.  
  1308.  
  1309. #endif
  1310.